// **************************************************************
// Com ++ Framework by the C++ World
// Please report defects: mailto:compp@cplusplusworld.com
// Please visit: http://www.cplusplusworld.com/socketlibrary.html
// **************************************************************

#include "SysPlusPlus/SysPlusPlus"
#include "ComPlusPlus/ComPlusPlus"


#include <string>
#include <strings.h>

int main(int argc, char *argv [] ) {

  const int TestPort = 31234;
  const int LOOPS = 100;

  try {
  	
    compp::SocketTcp server(TestPort);
    compp::SocketTcp * srv;

    compp::SocketTcp client;
    client.Connect ( "127.0.0.1", TestPort );

    srv = server.Accept();

    std::cout << "Client: ";
    std::cout <<  client.GetSockIPAddr()<< ":" << client.GetSockPort() 
	      <<  " connected to " 
	      << client.GetPeerSockIPAddr()<< ":" << client.GetPeerSockPort() 
	      << "\n";

    std::cout << "Server(Worker): GetSockIPAddr() GetSockPort() GetPeerSockIPAddr() GetPeerSockPort()";
    std::cout <<  srv->GetSockIPAddr()<< ":" << srv->GetSockPort() 
	      <<  " connected to " 
	      << srv->GetPeerSockIPAddr()<< ":" << srv->GetPeerSockPort() 
	      << "\n";


    std::cout << "Server Address" << srv->GetSocketAddress () << ":" << srv->GetSocketPort() << "\n";

    char c1 [10];
    char c2 [10];

    strcpy ( c1, "Hello") ;
    memset ((void*) c2, 0, sizeof ( c2 ) ); 

    
    client.Write ( c1, strlen (c1) );


    if ( !srv->PollRcv( 1000 ) ) {
      std::cout << " 1.) Polling is NOT OK\n";;
    } else {
      std::cout << " 1.) Polling is OK\n";
    }
    srv->Read  ( c2, sizeof ( c2 ) );

    std::cout << " 2.) (Should say "<<c1 <<" ) Says: " << c2 << "\n";

    std::string str1 = "" ;
    std::string str2 = "" ;
    
    for ( int i = 0; i < LOOPS; ++ i ) 
      str1 += "Hello World";

    char c[ 2000 ];

    int sent = 0;
    int rcvd = 0;
    std::cout << " 3.) Mass volume test (every dot means " << str1.length() * LOOPS <<  "bytes sent and received correctly)\n";
    for ( int j = 0; j < LOOPS; ++ j ){

      sent += client.Writen ( str1.c_str(), str1.length() ); 
      rcvd += srv->Readn  ( c, str1.length() ); 
      
      std::cout << "." ;
      std::cout.flush();
    }

    std::cout << "\n" ;
    std::cout << "  Sent " << sent << " Received " << rcvd << "\n";     
    client.Shutdown ( 2 );
    srv->Shutdown ( 2 );
    delete srv;
  } catch (  syspp::ComException e ) {
    perror ( "Accept"); 
    std::cout << "Exception" << e.what() << "\n";
  } catch ( ... ) {
    std::cout << "Exception\n";
  }

  try {
  	
  	compp::SocketTcp srv(TestPort+1) ;
  	compp::SocketTcp *s1;
  	compp::SocketTcp clnt;
  	compp::Poll Multiplexer;
      	
	Multiplexer.AddReadQueue(&srv);  	
    
	std::cout << " 4.) Multiplexer 1 (0 excpected ) got " << Multiplexer.Multiplexer(2000) << "\n";
	clnt.Connect("127.0.0.1", TestPort+1 );
	std::cout << " 4.) Multiplexer 2 (1 excpected ) got " << Multiplexer.Multiplexer(2000) << "\n";
  	s1 = srv.Accept();
	Multiplexer.AddReadQueue(s1);  	
	std::cout << " 4.) Multiplexer 3 (0 excpected ) got " << Multiplexer.Multiplexer(2000) << "\n";
  	s1->Write ( "Hello\n" );
  	Multiplexer.AddReadQueue(&clnt);  	
	std::cout << " 4.) Multiplexer 4 (1 excpected ) got " << Multiplexer.Multiplexer(2000) << "\n";
	clnt.Write ( "World\n" );  	
	std::cout << " 4.) Multiplexer 5 (2 excpected ) got " << Multiplexer.Multiplexer(2000) << "\n";
  	Multiplexer.EmptyReadQueue();
	std::cout << " 4.) Multiplexer 6 (0 excpected ) got " << Multiplexer.Multiplexer(2000) << "\n";
  	
  	
 	std::cout << "Listener (should be open): " << (srv.IsEOF() ? "closed\n" : "open\n") ;
  	std::cout << "Worker (should be open): " << (s1->IsEOF() ? "closed\n" : "open\n") ;
	std::cout << "Shutting down worker...\n";  	

	std::cout << "Closing Client ... Server should still be open\n";
  	clnt.Shutdown();
  	std::cout << "Listener(should be open): " << (srv.IsEOF() ? "closed\n" : "open\n") ;
  	std::cout << "Worker(should be open): " << (s1->IsEOF() ? "closed\n" : "open\n") ;
	
	char c[9000];
	memset ( (void*) c, 0, sizeof ( c ) ) ; 
	std::cout << "Read from closed socket should deliver the string World :"  << s1->Read(c, 100) << " " << c << "\n"; 
  	std::cout << "Listener(should still be open): " << (srv.IsEOF() ? "closed\n" : "open\n") ;
  	std::cout << "Worker(should be open): " << (s1->IsEOF() ? "closed\n" : "open\n") ;

	strcpy ( c, "" );
	std::cout << "Read from closed socket "  << s1->Read(c, 100) << ":" << c << "\n"; 
  	std::cout << "Listener (must be open): " << (srv.IsEOF() ? "closed\n" : "open\n") ;
  	std::cout << "Worker (must be closed now): " << (s1->IsEOF() ? "closed\n" : "open\n") ;
	delete s1;
  	
  	compp::SocketTcp srv2(TestPort+2) ;
  	compp::SocketTcp *s2;
  	compp::SocketTcp clnt2;
	clnt2.SetReadAhead( true );

	clnt2.Connect("127.0.0.1", TestPort+2 );
	std::cout << " 5.) Read Ahead Cache Test: connect\n";
  	s2 = srv2.Accept();
	
	std::cout << " 5.) Read Ahead Cache Test: accepted\n"; 
  	s2->Write ( "111111\n" );
	clnt2.Read ( c, 1 );
	c[1] = 0;
	std::cout << " 5.) Read Ahead Cache Test: Read () 1 expected got " << c << "\n";
	clnt2.Shutdown ( );

	clnt2.Connect("127.0.0.1", TestPort+2 );
  	s2 = srv2.Accept();
	std::cout << " 5.) Read Ahead Cache Test: accepted\n";

  	s2->Write ( "2222222\n" );
	clnt2.Read ( c, 1 );
	c[1] = 0;
	std::cout << " 5.) Read Ahead Cache Test: Read () 2 expected got " << c << "\n";
	clnt2.Shutdown ( );

  } catch  ( syspp::ComException e ) {
    perror ( "SocketTest"); 
    std::cout << "Exception" << e.what() << "\n";
  }

  return 0;
}
